package cn.shengchao.examstar.ai.application.service;

import cn.shengchao.examstar.ai.application.dto.StudyCalendarDTO;
import cn.shengchao.examstar.ai.application.dto.StudyDayDTO;
import cn.shengchao.examstar.ai.infrastructure.dao.AiStudyDayDao;
import cn.shengchao.examstar.ai.infrastructure.dao.po.AiStudyDay;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 学习日程服务
 * 处理学习日程相关的应用层逻辑
 */
@Service
@Slf4j
public class AiStudyDayService {

    @Autowired
    private AiStudyDayDao aiStudyDayDao;

    /**
     * 获取指定日期范围内的学习日程
     * @param userId 用户ID
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @param studyPlanId 学习计划ID (可选)
     * @return 学习日程列表
     */
    public List<StudyDayDTO> getStudyDays(Long userId, LocalDate startDate, LocalDate endDate, Long studyPlanId) {
        log.info("查询用户[{}]在{}至{}期间的学习日程，学习计划ID: {}", userId, startDate, endDate, studyPlanId);

        // 转换日期为Date类型
        Date start = Date.from(startDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
        Date end = Date.from(endDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).minusNanos(1).toInstant());

        // 构建查询条件
        LambdaQueryWrapper<AiStudyDay> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(AiStudyDay::getUserId, userId)
                .ge(AiStudyDay::getDate, start)
                .le(AiStudyDay::getDate, end);

        // 如果指定了学习计划ID，则添加过滤条件
        if (studyPlanId != null) {
            queryWrapper.eq(AiStudyDay::getAiStudyPlanId, studyPlanId);
        }

        // 执行查询
        List<AiStudyDay> studyDays = aiStudyDayDao.selectList(queryWrapper);

        // 转换为DTO
        return studyDays.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * 获取学习日历
     * @param userId 用户ID
     * @param yearMonth 年月(格式: yyyy-MM)
     * @param studyPlanId 学习计划ID (可选)
     * @return 学习日历DTO
     */
    public StudyCalendarDTO getStudyCalendar(Long userId, String yearMonth, Long studyPlanId) {
        log.info("查询用户[{}]在{}月的学习日历，学习计划ID: {}", userId, yearMonth, studyPlanId);

        // 解析年月
        YearMonth ym = YearMonth.parse(yearMonth, DateTimeFormatter.ofPattern("yyyy-MM"));
        LocalDate startDate = ym.atDay(1);
        LocalDate endDate = ym.atEndOfMonth();

        // 查询该月的所有学习日程
        List<StudyDayDTO> studyDays = getStudyDays(userId, startDate, endDate, studyPlanId);

        // 按日期分组
        Map<String, List<StudyDayDTO>> calendarEntries = studyDays.stream()
                .collect(Collectors.groupingBy(
                        day -> day.getDate().toLocalDate().format(DateTimeFormatter.ISO_DATE)
                ));

        // 确保日历包含当月所有日期
        Map<String, List<StudyDayDTO>> fullCalendarEntries = new TreeMap<>();
        // 初始化所有日期为空列表
        for (int day = 1; day <= endDate.getDayOfMonth(); day++) {
            String dateKey = LocalDate.of(ym.getYear(), ym.getMonth(), day).format(DateTimeFormatter.ISO_DATE);
            fullCalendarEntries.put(dateKey, new ArrayList<>());
        }
        // 填充有数据的日期
        fullCalendarEntries.putAll(calendarEntries);

        // 计算统计数据
        int totalStudyTimeMinutes = studyDays.stream()
                .mapToInt(StudyDayDTO::getStudyTimeMinutes)
                .sum();

        int completedTasksCount = (int) studyDays.stream()
                .filter(StudyDayDTO::getCompleted)
                .count();

        // 构建日历DTO
        return StudyCalendarDTO.builder()
                .yearMonth(yearMonth)
                .userId(String.valueOf(userId))
                .studyPlanId(studyPlanId != null ? String.valueOf(studyPlanId) : null)
                .calendarEntries(fullCalendarEntries)
                .totalStudyTimeMinutes(totalStudyTimeMinutes)
                .completedTasksCount(completedTasksCount)
                .totalTasksCount(studyDays.size())
                .build();
    }

    /**
     * 创建或更新学习日程
     * @param studyDayDTO 学习日程DTO
     * @return 创建或更新后的学习日程DTO
     */
    @Transactional
    public StudyDayDTO createOrUpdateStudyDay(StudyDayDTO studyDayDTO) {
        log.info("创建或更新学习日程: {}", studyDayDTO);

        // 转换为PO对象
        AiStudyDay aiStudyDay = convertToPO(studyDayDTO);

        // 检查是否存在
        boolean isUpdate = aiStudyDay.getId() != null;

        if (isUpdate) {
            // 更新
            aiStudyDayDao.updateById(aiStudyDay);
            log.info("更新学习日程成功，ID: {}", aiStudyDay.getId());
        } else {
            // 新增
            aiStudyDayDao.insert(aiStudyDay);
            log.info("创建学习日程成功，ID: {}", aiStudyDay.getId());
        }

        // 返回更新后的DTO
        return convertToDTO(aiStudyDay);
    }

    /**
     * 批量创建学习日程
     * @param studyDayDTOs 学习日程DTO列表
     * @return 创建后的学习日程DTO列表
     */
    @Transactional
    public List<StudyDayDTO> batchCreateStudyDays(List<StudyDayDTO> studyDayDTOs) {
        log.info("批量创建学习日程，数量: {}", studyDayDTOs.size());

        if (studyDayDTOs.isEmpty()) {
            log.warn("批量创建学习日程失败：传入的学习日程列表为空");
            return Collections.emptyList();
        }

        List<AiStudyDay> aiStudyDays = new ArrayList<>();
        
        // 转换为PO对象并逐个插入
        for (StudyDayDTO dto : studyDayDTOs) {
            AiStudyDay aiStudyDay = convertToPO(dto);
            // 添加到结果列表
            aiStudyDays.add(aiStudyDay);
            log.debug("创建学习日程: id={}, 日期={}, 任务={}", 
                    aiStudyDay.getId(), aiStudyDay.getDate(), aiStudyDay.getJobName());
        }
        // 插入数据库
        aiStudyDayDao.insert(aiStudyDays);
        log.info("成功批量创建学习日程，数量: {}", aiStudyDays.size());
        
        // 返回更新后的DTO列表
        return aiStudyDays.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * 根据模板批量创建学习日程
     * @param userId 用户ID
     * @param studyPlanId 学习计划ID
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @param template 学习日程模板
     * @return 创建后的学习日程DTO列表
     */
    @Transactional
    public List<StudyDayDTO> batchCreateStudyDaysFromTemplate(Long userId, Long studyPlanId,
                                                              LocalDate startDate, LocalDate endDate,
                                                              StudyDayDTO template) {
        log.info("根据模板批量创建学习日程，用户ID: {}，学习计划ID: {}，开始日期: {}，结束日期: {}",
                userId, studyPlanId, startDate, endDate);

        if (startDate.isAfter(endDate)) {
            throw new IllegalArgumentException("开始日期不能晚于结束日期");
        }

        List<StudyDayDTO> studyDayDTOs = new ArrayList<>();
        LocalDate currentDate = startDate;

        while (!currentDate.isAfter(endDate)) {
            // 基于模板创建新的学习日程
            StudyDayDTO studyDayDTO = StudyDayDTO.builder()
                    .date(currentDate.atStartOfDay())
                    .jobName(template.getJobName())
                    .knowledgePointId(template.getKnowledgePointId())
                    .knowledgePoint(template.getKnowledgePoint())
                    .studyTimeMinutes(template.getStudyTimeMinutes())
                    .studyPlanId(String.valueOf(studyPlanId))
                    .userId(String.valueOf(userId))
                    .completed(false)
                    .build();

            studyDayDTOs.add(studyDayDTO);
            currentDate = currentDate.plusDays(1);
        }

        // 批量创建
        return batchCreateStudyDays(studyDayDTOs);
    }

    /**
     * 标记学习日程为已完成
     * @param studyDayId 学习日程ID
     * @return 更新后的学习日程DTO
     */
    @Transactional
    public StudyDayDTO completeStudyDay(Long studyDayId) {
        log.info("标记学习日程[{}]为已完成", studyDayId);

        // 查询学习日程
        AiStudyDay aiStudyDay = aiStudyDayDao.selectById(studyDayId);
        if (aiStudyDay == null) {
            throw new IllegalArgumentException("学习日程不存在: " + studyDayId);
        }

        // 更新状态
        AiStudyDay updateEntity = new AiStudyDay();
        updateEntity.setId(studyDayId);
        updateEntity.setCompleted(true);
        updateEntity.setCompletedTime(new Date());

        aiStudyDayDao.updateById(updateEntity);
        log.info("学习日程[{}]已标记为完成", studyDayId);

        // 重新查询并返回
        aiStudyDay = aiStudyDayDao.selectById(studyDayId);
        return convertToDTO(aiStudyDay);
    }

    /**
     * 删除学习日程
     * @param studyDayId 学习日程ID
     */
    @Transactional
    public void deleteStudyDay(Long studyDayId) {
        log.info("删除学习日程[{}]", studyDayId);

        // 查询学习日程
        AiStudyDay aiStudyDay = aiStudyDayDao.selectById(studyDayId);
        if (aiStudyDay == null) {
            throw new IllegalArgumentException("学习日程不存在: " + studyDayId);
        }

        // 删除
        aiStudyDayDao.deleteById(studyDayId);
        log.info("学习日程[{}]已删除", studyDayId);
    }

    /**
     * 根据学习计划ID查询学习日程
     * @param studyPlanId 学习计划ID
     * @return 学习日程列表
     */
    public List<StudyDayDTO> findByStudyPlanId(String studyPlanId) {
        log.info("根据学习计划ID[{}]查询学习日程", studyPlanId);
        
        if (studyPlanId == null || studyPlanId.isEmpty()) {
            log.warn("学习计划ID为空，返回空列表");
            return Collections.emptyList();
        }
        
        try {
            Long planId = Long.valueOf(studyPlanId);
            
            // 构建查询条件
            LambdaQueryWrapper<AiStudyDay> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(AiStudyDay::getAiStudyPlanId, planId);
            
            // 执行查询
            List<AiStudyDay> studyDays = aiStudyDayDao.selectList(queryWrapper);
            log.info("学习计划[{}]下的学习日程数量: {}", studyPlanId, studyDays.size());
            
            // 转换为DTO
            return studyDays.stream()
                    .map(this::convertToDTO)
                    .collect(Collectors.toList());
        } catch (NumberFormatException e) {
            log.error("学习计划ID格式错误: {}", studyPlanId, e);
            return Collections.emptyList();
        }
    }

    /**
     * 将实体对象转换为DTO
     */
    private StudyDayDTO convertToDTO(AiStudyDay aiStudyDay) {
        if (aiStudyDay == null) {
            return null;
        }

        LocalDateTime dateTime = null;
        if (aiStudyDay.getDate() != null) {
            dateTime = aiStudyDay.getDate().toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();
        }

        LocalDateTime completedTime = null;
        if (aiStudyDay.getCompletedTime() != null) {
            completedTime = aiStudyDay.getCompletedTime().toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();
        }

        LocalDateTime createTime = null;
        if (aiStudyDay.getCreateTime() != null) {
            createTime = aiStudyDay.getCreateTime().toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();
        }

        LocalDateTime updateTime = null;
        if (aiStudyDay.getUpdateTime() != null) {
            updateTime = aiStudyDay.getUpdateTime().toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();
        }

        return StudyDayDTO.builder()
                .id(String.valueOf(aiStudyDay.getId()))
                .date(dateTime)
                .jobName(aiStudyDay.getJobName())
                .knowledgePointId(String.valueOf(aiStudyDay.getKnowledgePointId()))
                .knowledgePoint(aiStudyDay.getKnowledgePoint())
                .studyTimeMinutes(aiStudyDay.getTime() != null ? aiStudyDay.getTime().intValue() : null)
                .studyPlanId(String.valueOf(aiStudyDay.getAiStudyPlanId()))
                .userId(String.valueOf(aiStudyDay.getUserId()))
                .completed(aiStudyDay.getCompleted())
                .completedTime(completedTime)
                .createTime(createTime)
                .updateTime(updateTime)
                .build();
    }

    /**
     * 将DTO转换为实体对象
     */
    private AiStudyDay convertToPO(StudyDayDTO dto) {
        if (dto == null) {
            return null;
        }

        AiStudyDay aiStudyDay = new AiStudyDay();

        if (dto.getId() != null && !dto.getId().isEmpty()) {
            aiStudyDay.setId(Long.valueOf(dto.getId()));
        }

        if (dto.getDate() != null) {
            aiStudyDay.setDate(Date.from(dto.getDate()
                    .atZone(ZoneId.systemDefault())
                    .toInstant()));
        }

        aiStudyDay.setJobName(dto.getJobName());

        if (dto.getKnowledgePointId() != null && !dto.getKnowledgePointId().isEmpty()) {
            aiStudyDay.setKnowledgePointId(Long.valueOf(dto.getKnowledgePointId()));
        }

        aiStudyDay.setKnowledgePoint(dto.getKnowledgePoint());

        if (dto.getStudyTimeMinutes() != null) {
            aiStudyDay.setTime(dto.getStudyTimeMinutes().longValue());
        }

        if (dto.getStudyPlanId() != null && !dto.getStudyPlanId().isEmpty()) {
            aiStudyDay.setAiStudyPlanId(Long.valueOf(dto.getStudyPlanId()));
        }

        if (dto.getUserId() != null && !dto.getUserId().isEmpty()) {
            aiStudyDay.setUserId(Long.valueOf(dto.getUserId()));
        }

        aiStudyDay.setCompleted(dto.getCompleted());

        if (dto.getCompletedTime() != null) {
            aiStudyDay.setCompletedTime(Date.from(dto.getCompletedTime()
                    .atZone(ZoneId.systemDefault())
                    .toInstant()));
        }

        return aiStudyDay;
    }
} 